﻿/*
Project Name : Menfram
Module Name  : Menfram
Date  : 07/06/2013
responsible : Mateus Neto
Obs  : The license of this software is Mozilla Public License 1.1 
contact : mentrixmax@gmail.com
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Menfram.Entity.Interface;
using Menfram.DAL.Reflection;
using System.Collections;
using System.Reflection;
using System.Data.Common;

namespace Menfram.Reflection
{

    /// <summary>
    /// Class that uses reflection to discover the fields and attributes of a class.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Configurations<T>
    {

        /// <summary>
        /// Method with read the class and return the name of atributes 
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public static Table getTableConfiguration(Type e)
        {
            System.Attribute[] attrs = System.Attribute.GetCustomAttributes(e, typeof(Table));
            var lowNums = from n in attrs select ((Table)n);
            return lowNums.Single();
        }


        public static String getFieldPKeyName(Type t)
        {
            PropertyInfo[] list = t.GetProperties();

            foreach (PropertyInfo p in list)
            {
                object[] attributes = p.GetCustomAttributes(typeof(Key), false);
                for (int i = 0; i < attributes.Length; i++)
                {
                    Key ad = (Key)attributes[i];
                    if (ad.Pk)
                    {
                        return p.Name;
                    }
                }
            }

            return "";
        }

        public static String getColumnNameByField(Type t, String field)
        {
            PropertyInfo[] list = t.GetProperties();

            foreach (PropertyInfo p in list)
            {
                if (p.Name.Equals(field))
                {

                    object[] attributes = p.GetCustomAttributes(typeof(Field), false);
                    for (int i = 0; i < attributes.Length; i++)
                    {
                        Field ad = (Field)attributes[i];
                        if (!ad.FieldName.Equals(field))
                        {
                            return ad.FieldName;
                        }
                    }
                    break;
                }
            }
            return field;
        }

        public static String getFieldKeyName(Type t)
        {
            PropertyInfo[] list = t.GetProperties();

            foreach (PropertyInfo p in list)
            {
                object[] attributes = p.GetCustomAttributes(typeof(Key), false);
                for (int i = 0; i < attributes.Length; i++)
                {
                    Key ad = (Key)attributes[i];
                    if (ad.KKey)
                    {
                        return p.Name;
                    }
                }
            }
            return "";
        }


        public static Hashtable getMapsOneToMany(Type t)
        {
            PropertyInfo[] list = t.GetProperties();
            Hashtable maps = new Hashtable();
            foreach (PropertyInfo p in list)
            {
                object[] attributes = p.GetCustomAttributes(typeof(OneToMany), false);
                if (attributes.Length > 0)
                {
                    maps.Add(p, attributes);
                }
            }
            return maps;
        }

        public static Hashtable getMapsOneToOne(Type t)
        {
            PropertyInfo[] list = t.GetProperties();
            Hashtable maps = new Hashtable();
            foreach (PropertyInfo p in list)
            {
                object[] attributes = p.GetCustomAttributes(typeof(OneToOne), false);
                if (attributes.Length > 0)
                {
                    maps.Add(p, attributes);
                }
            }
            return maps;
        }
        /// <summary>
        /// Method with read the class and return the hashtable filled witch value and key
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static Hashtable getFildConfiguration(T t)
        {
            Hashtable hs = new Hashtable();
            PropertyInfo[] list = t.GetType().GetProperties();
            foreach (PropertyInfo p in list)
            {
                object[] attributes = p.GetCustomAttributes(typeof(Field), false);
                object[] noattributes = p.GetCustomAttributes(typeof(NoField), false);
                object[] mappeds = p.GetCustomAttributes(typeof(OneToMany), false);
                object[] mappedsOne = p.GetCustomAttributes(typeof(OneToOne), false);

                if (attributes.Length > 0)
                {
                    foreach (object attribute in attributes)
                    {
                        Field ad = (Field)attribute;
                        object retor = getProperty(t, p.Name);
                        if (retor != null)
                        {
                            hs.Add(ad.FieldName, retor);
                        }
                    }
                }
                else
                {
                    if (noattributes.Length == 0 && mappeds.Length == 0 && mappedsOne.Length == 0)
                    {
                        object retor = getProperty(t, p.Name);
                        hs.Add(p.Name, retor);
                    }
                }
            }
            return hs;
        }


        /// <summary>
        /// Method with read the class and return the hashtable filled witch value and key
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static Hashtable getFildConfiguration(IEntity t)
        {
            Hashtable hs = new Hashtable();
            PropertyInfo[] list = t.GetType().GetProperties();
            foreach (PropertyInfo p in list)
            {
                object[] attributes = p.GetCustomAttributes(typeof(Field), false);
                object[] noattributes = p.GetCustomAttributes(typeof(NoField), false);
                object[] mappeds = p.GetCustomAttributes(typeof(OneToMany), false);
                object[] mappedsOne = p.GetCustomAttributes(typeof(OneToOne), false);

                if (attributes.Length > 0)
                {
                    foreach (object attribute in attributes)
                    {
                        Field ad = (Field)attribute;
                        object retor = getProperty(t, p.Name);
                        if (retor != null)
                        {
                            hs.Add(ad.FieldName, retor);
                        }
                    }
                }
                else
                {
                    if (noattributes.Length == 0 && mappeds.Length == 0 && mappedsOne.Length == 0)
                    {
                        object retor = getProperty(t, p.Name);
                        hs.Add(p.Name, retor);
                    }
                }
            }
            return hs;
        }

        /// <summary>
        /// Method with get the value of the atribute of the object
        /// </summary>
        /// <param name="a"></param>
        /// <param name="prop"></param>
        /// <returns></returns>
        public static object getProperty(T a, String prop)
        {
            PropertyInfo propriedade = null;
            propriedade = a.GetType().GetProperty(prop);
            return propriedade.GetValue(a, null);
        }

        /// <summary>
        /// Method with get the value of the atribute of the object
        /// </summary>
        /// <param name="a"></param>
        /// <param name="prop"></param>
        /// <returns></returns>
        public static object getProperty(IEntity a, String prop)
        {
            PropertyInfo propriedade = null;
            propriedade = a.GetType().GetProperty(prop);
            return propriedade.GetValue(a, null);
        }

        public static void setProperty(object obj, string name, object value)
        {
            PropertyInfo[] listPro = obj.GetType().GetProperties();
            for (int i = 0; i < listPro.Length; i++)
            {
                if (listPro[i].Name.Equals(name))
                {
                    PropertyInfo pInfo = listPro[i];
                    pInfo.SetValue(obj, value, null);
                    break;
                }
            }

        }

        /// <summary>
        /// Method with put the value of the atribute in the object.
        /// </summary>
        /// <param name="pInfo"></param>
        /// <param name="propertyName"></param>
        /// <param name="propertyValue"></param>
        /// <param name="objectToSetValue"></param>
        public static void setProperty(PropertyInfo pInfo, string propertyName, object propertyValue, object objectToSetValue)
        {
            System.Type pType = pInfo.PropertyType;
            if (propertyValue == DBNull.Value) {
                return;
            }
            if (pType == typeof(string) || pType == typeof(String))
            {
                pInfo.SetValue(objectToSetValue, propertyValue, null);
            }
            else if (pType == typeof(bool) || pType == typeof(bool?) || pType == typeof(Boolean) || pType == typeof(Boolean?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToBoolean(propertyValue), null);
            }
            else if (pType == typeof(byte) || pType == typeof(byte?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToByte(propertyValue), null);
            }
            else if (pType == typeof(sbyte) || pType == typeof(sbyte?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToSByte(propertyValue), null);
            }
            else if (pType == typeof(short) || pType == typeof(short?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToInt16(propertyValue), null);
            }
            else if (pType == typeof(ushort) || pType == typeof(ushort?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToUInt16(propertyValue), null);
            }

            else if (pType == typeof(int?) || pType == typeof(int))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToInt32(propertyValue), null);
            }
            else if (pType == typeof(uint) || pType == typeof(uint?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToUInt32(propertyValue), null);
            }
            else if (pType == typeof(long?) || pType == typeof(long?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToInt64(propertyValue), null);
            }
            else if (pType == typeof(ulong) || pType == typeof(ulong?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToUInt32(propertyValue), null);
            }

            else if (pType == typeof(float?) || pType == typeof(float) || pType == typeof(Single) || pType == typeof(Single?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToSingle(propertyValue), null);
            }
            else if (pType == typeof(double?) || pType == typeof(double?) || pType == typeof(Double) || pType == typeof(Double?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToDouble(propertyValue), null);
            }
            else if (pType == typeof(decimal?) || pType == typeof(decimal?) || pType == typeof(Decimal) || pType == typeof(Decimal?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToDecimal(propertyValue), null);
            }
            else if (pType == typeof(DateTime?) || pType == typeof(DateTime))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToDateTime(propertyValue), null);
            }
            else if (pType == typeof(char?) || pType == typeof(char) || pType == typeof(Char) || pType == typeof(Char?))
            {
                pInfo.SetValue(objectToSetValue, Convert.ToChar(propertyValue), null);
            }
            if (pType == typeof(DBNull))
            {
                pInfo.SetValue(objectToSetValue, null, null);
            }
            else if (pType == typeof(System.Drawing.Image))
            {
                pInfo.SetValue(objectToSetValue, propertyName, null);
            }
            if (pType == typeof(byte[]))
            {
                byte[] bytes = (byte[])propertyValue;
                pInfo.SetValue(objectToSetValue, bytes, null);
            }


        }

        /// <summary>
        /// Method with filled the copy te data of the databases to entity
        /// </summary>
        /// <param name="db"></param>
        /// <param name="nameObject"></param>
        /// <returns></returns>
        public static T getEntityFilled(DbDataReader db, string nameObject)
        {
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(typeof(T));
            T valor = (T)assembly.CreateInstance(nameObject);

            PropertyInfo[] list = valor.GetType().GetProperties();
            foreach (PropertyInfo p in list)
            {
                object[] attributes = p.GetCustomAttributes(typeof(Field), false);

                object[] noattributes = p.GetCustomAttributes(typeof(NoField), false);

                object[] mapeds = p.GetCustomAttributes(typeof(OneToMany), false);

                object[] mapedsOne = p.GetCustomAttributes(typeof(OneToOne), false);


                if (attributes.Length > 0)
                {
                    foreach (object attribute in attributes)
                    {
                        Field ad = (Field)attribute;
                        setProperty(p, p.Name, db[ad.FieldName], valor);
                    }
                }
                else
                {
                    if (noattributes.Length == 0 && mapeds.Length == 0 && mapedsOne.Length == 0)
                    {
                        setProperty(p, p.Name, db[p.Name], valor);
                    }
                }
            }
            return valor;
        }

        /// <summary>
        /// Method with filled the copy te data of the databases to entity
        /// </summary>
        /// <param name="db"></param>
        /// <param name="nameObject"></param>
        /// <returns></returns>
        public static object getEntityFilled(DbDataReader db, string nameObject, Type novo)
        {
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetAssembly(novo);
            var valor = assembly.CreateInstance(nameObject);

            PropertyInfo[] list = valor.GetType().GetProperties();
            foreach (PropertyInfo p in list)
            {
                object[] attributes = p.GetCustomAttributes(typeof(Field), false);

                object[] noattributes = p.GetCustomAttributes(typeof(NoField), false);

                object[] mapeds = p.GetCustomAttributes(typeof(OneToMany), false);

                object[] mapedsOne = p.GetCustomAttributes(typeof(OneToOne), false);


                if (attributes.Length > 0)
                {
                    foreach (object attribute in attributes)
                    {
                        Field ad = (Field)attribute;
                        setProperty(p, p.Name, db[ad.FieldName], valor);
                    }
                }
                else
                {
                    if (noattributes.Length == 0 && mapeds.Length == 0 && mapedsOne.Length == 0)
                    {
                        setProperty(p, p.Name, db[p.Name], valor);
                    }
                }
            }
            return valor;
        }



    }


}
